﻿'/*
' * FAHWatch7  Copyright Marvin Westmaas ( mtm )
' *
' * This program is free software; you can redistribute it and/or
' * modify it under the terms of the GNU General Public License
' * as published by the Free Software Foundation; version 2
' * of the License. See the included file GPLv2.TXT.
' * 
' * This program is distributed in the hope that it will be useful,
' * but WITHOUT ANY WARRANTY; without even the implied warranty of
' * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' * GNU General Public License for more details.
' * 
' * You should have received a copy of the GNU General Public License
' * along with this program; if not, write to the Free Software
' * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
' */
'/*	
'Imports m_hwinfo.clsHWInfo
'Imports gpuInfo.gpuInfo
Imports System.Text
Imports System.IO
Public Class clsClients
#Region "Client definition"
    Public Class clsClient
#Region "Object definitions and storage"
        Public ClientName As String = "local"
        Public ClientLocation As String = ""
        Public ClientConfig As clsClientConfig
        Public ClientInfo As clsClientInfo
        Public FCPort As String = ""
        Public PWD As String = ""
        Public FWPort As String = ""
        Public Enabled As Boolean = True
        Public Sub New(ByVal Name As String, ByVal Location As String)
            ClientName = Name
            ClientLocation = Location
        End Sub
        Public Class clsLogFile
            Private _ClientName As String = ""
            Public ReadOnly Property ClientName As String
                Get
                    Return _ClientName
                End Get
            End Property
            Public Sub New(ByVal ClientName As String)
                _ClientName = ClientName
            End Sub
            Public ReadOnly Property AllDone As Boolean
                Get
                    'Check if all wu's have been fully parsed!
                    Dim bRet As Boolean = True
                    Try
                        For Each wu As clsWU In dWU.Values
                            If wu.CoreStatus = "" Then
                                bRet = False
                                Exit For
                            End If
                        Next
                    Catch ex As Exception

                    End Try
                    Return bRet
                End Get
            End Property
            'Extending logfile structure with log information
            Public Class clsWU
                'Line identifier 
                Public lineIndex As Int32 = 0
                Public LineDT As DateTime = #1/1/2000#
                Public FileName As String = ""
#Region "FrameInfo"
                Public Class clsFrame
                    Private dtFrame As DateTime
                    Private strFrame As String
                    Public Sub New(ByVal Line As String, ByVal FrameDT As DateTime)
                        strFrame = Line
                        dtFrame = FrameDT
                    End Sub
                    Public ReadOnly Property LogString As String
                        Get
                            Return strFrame
                        End Get
                    End Property
                    Public ReadOnly Property strPercentage As String
                        Get
                            Dim rVal As String = ""
                            For xIP As Int32 = strFrame.IndexOf("%") To 1 Step -1
                                If strFrame.Substring(xIP, 1) = " " Or strFrame.Substring(xIP, 1) = "(" Then
                                    rVal = strFrame.Substring(xIP, strFrame.IndexOf("%") - xIP).Trim.Replace("(", "").Trim
                                    Exit For
                                End If
                            Next
                            Return rVal
                        End Get
                    End Property
                    Public ReadOnly Property Percentage As Short
                        Get
                            Return CShort(strPercentage)
                        End Get
                    End Property
                    Public ReadOnly Property FrameDT As DateTime
                        Get
                            Return dtFrame
                        End Get
                    End Property
                End Class
                Private lstFrames As New Dictionary(Of String, clsFrame)
                Public Sub AddFrame(ByVal Frame As String, ByVal dtFrame As DateTime)
                    Try
                        If lstFrames.Keys.Contains(Frame) Then Exit Sub
                        Dim nFrame As New clsFrame(Frame, dtFrame)
                        'Not all wu's print 0%, but I'll be using wu.dtStarted to wu.frames(0) to wu.frames(99)
                        If nFrame.Percentage = 0 Then Exit Sub
                        For Each sFrame In lstFrames.Values
                            If sFrame.Percentage = nFrame.Percentage Then Exit Sub
                        Next
                        lstFrames.Add(Frame, nFrame)
                    Catch ex As Exception
                        WriteError(ex.Message, Err)
                    End Try
                End Sub
                Public ReadOnly Property Frames As List(Of clsFrame)
                    Get
                        Dim rVal As New List(Of clsFrame)
                        rVal.AddRange(lstFrames.Values)
                        Return rVal
                    End Get
                End Property
                Public Sub ClearFrames(Optional iPercentage As Int32 = -1)
                    Try
                        If iPercentage = -1 Then
                            lstFrames.Clear()
                        Else
                            Dim lKeys As New List(Of String)
                            For xInt As Int32 = iPercentage To lstFrames.Count - 1
                                lKeys.Add(lstFrames.Keys(xInt))
                            Next
                            For Each Key In lKeys
                                lstFrames.Remove(Key)
                            Next
                        End If
                    Catch ex As Exception
                        Console.WriteLine("Clearing frames has failed! " & iPercentage & " - " & Frames(Frames.Count - 1).strPercentage)
                        WriteError(ex.Message, Err)
                    End Try
                End Sub
#End Region
#Region "Added properties due to new parser"
                Public ClientName As String = ""
                Public ConfigID As String = ""
                Public LogDT As DateTime = #1/1/2000#
                Public iLogLine As Int32 = 0 'Added this for live view, store in ActiveWU table to parse from this wu
                Public ReadOnly Property ClientConfig As clsClientConfig.clsConfiguration
                    'ClientConfig per wu is read back from DB 
                    Get
                        Try
                            Return sqdata.ClientConfigBeforeDT(ClientName, dtDownloaded)
                        Catch ex As Exception
                            WriteError(ex.Message, Err)
                            Return New clsClientConfig.clsConfiguration
                        End Try
                    End Get
                End Property
                Public ReadOnly Property ClientInfo As clsClientInfo.FAHClientInfo
                    Get
                        Try
                            Return sqdata.ClientInfoBeforeDT(ClientName, dtDownloaded)
                        Catch ex As Exception
                            WriteError(ex.Message, Err)
                            Return New clsClientInfo.FAHClientInfo
                        End Try
                    End Get
                End Property
                Public ReadOnly Property Diagnostics As String
                    Get
                        Try
                            Return ""
                            'Throw New NotImplementedException
                        Catch ex As Exception
                            WriteError(ex.Message, Err)
                            Return ""
                        End Try
                    End Get
                End Property
                Public UploadSize As String = ""
                Public dtStartUpload As DateTime = #1/1/2000#
                Private _iUploadSize As Double = 0
                Private _iUploadSpeed As Double = 0
                Public ReadOnly Property tsUpload As TimeSpan
                    Get
                        Try
                            If dtSubmitted = #1/1/2000# Or dtStartUpload = #1/1/2000# Then
                                Return New TimeSpan(0)
                            Else
                                Return dtSubmitted.Subtract(dtStartUpload)
                            End If
                        Catch ex As Exception
                            WriteError(ex.Message, Err)
                        End Try
                    End Get
                End Property
                Public Property iUploadSize As Double 'Always in bytes ( changed from KiB )
                    Get
                        Try
                            If _iUploadSize <> 0 Then Return _iUploadSize
                            If UploadSize = "" Then Return 0
                            If UploadSize.Contains("KiB") Then
                                If Not CDbl(CDbl(UploadSize.Replace("KiB", "")) * 1024).ToString.Contains(".") Then
                                    _iUploadSize = CDbl(CDbl(UploadSize.Replace("KiB", "")) * 1024)
                                Else
                                    _iUploadSize = CDbl((CDbl(UploadSize.Replace("KiB", "")) * 1024).ToString.Substring(0, (CDbl(UploadSize.Replace("KiB", "")) * 1024).ToString.IndexOf(".")))
                                End If
                                Return _iUploadSize
                            ElseIf UploadSize.Contains("MiB") Then
                                If Not (CDbl(UploadSize.Replace("MiB", "")) * 1024 * 1024).ToString.Contains(".") Then
                                    _iUploadSize = CDbl(UploadSize.Replace("MiB", "")) * 1024 * 1024
                                Else
                                    _iUploadSize = CDbl((CDbl(UploadSize.Replace("MiB", "")) * 1024 * 1024).ToString.Substring(0, (CDbl(UploadSize.Replace("MiB", "")) * 1024 * 1024).ToString.IndexOf(".")))
                                End If
                                Return _iUploadSize
                            ElseIf UploadSize.Contains("B") Then
                                If Not CDbl(UploadSize.Replace("B", "")).ToString.Contains(".") Then
                                    _iUploadSize = CDbl(UploadSize.Replace("B", ""))
                                Else
                                    _iUploadSize = CDbl(CDbl(UploadSize.Replace("B", "")).ToString.Substring(0, CDbl(UploadSize.Replace("B", "")).ToString.IndexOf(".")).ToString)

                                End If
                                Return _iUploadSize
                            End If
                            Return 0
                        Catch ex As Exception
                            Return 0
                        End Try
                    End Get
                    Set(value As Double)
                        _iUploadSize = value
                    End Set
                End Property
                Public Property iUploadSpeed As Double 'Always xxxxxB/s ( format string when displaying )
                    Get
                        Try
                            'Check
                            If _iUploadSpeed <> 0 Then Return _iUploadSpeed
                            If iUploadSize = 0 Then Return 0
                            Dim tsUpload As TimeSpan = dtSubmitted.Subtract(dtStartUpload)
                            If tsUpload.TotalSeconds < 1 Then tsUpload.Add(New TimeSpan(0, 0, 1))
                            Return iUploadSize / tsUpload.TotalSeconds
                        Catch ex As Exception
                            WriteLog("Couldn't calculate upload speed.")
                            Return iUploadSize
                        End Try
                    End Get
                    Set(value As Double)
                        _iUploadSpeed = value
                    End Set
                End Property
                Public ReadOnly Property UploadSpeed As String
                    Get
                        Try
                            If dtSubmitted = dtStartUpload Then
                                Return (UploadSize & "/s")
                            ElseIf iUploadSpeed < 1024 Then
                                Return Math.Round(iUploadSpeed, 2).ToString & "B/s"
                            ElseIf iUploadSpeed > 1024 And iUploadSpeed < 1024 * 1024 Then
                                Return Math.Round(iUploadSpeed / 1024, 2).ToString & "KiB/s"
                            Else
                                Return Math.Round(iUploadSpeed / 1024 / 1024, 2).ToString & "MiB/s"
                            End If
                        Catch ex As Exception
                            Return ""
                        End Try
                    End Get
                End Property
                Public ReadOnly Property tsTPF As TimeSpan
                    Get
                        Try
                            If Frames.Count > 0 Then
                                Dim tsTmp As TimeSpan, strAvg As String = String.Empty
                                Dim tsFrame As New TimeSpan
                                For xInt As Int32 = Frames.Count - 1 To 1 Step -1
                                    tsFrame = tsFrame.Add(Frames(xInt).FrameDT.Subtract(Frames(xInt - 1).FrameDT))
                                Next
                                tsTmp = New TimeSpan(CLng(tsFrame.Ticks / Frames.Count))
                                Return tsTmp
                            Else
                                Return New TimeSpan(0)
                            End If
                        Catch ex As Exception
                            WriteError(ex.Message, Err)
                            Return New TimeSpan(0)
                        End Try
                    End Get
                End Property
                Public ReadOnly Property TPF As String
                    Get
                        Try
                            If tsTPF.TotalSeconds > 0 Then
                                Dim strAvg As String = String.Empty
                                If tsTPF.Days > 0 Then
                                    strAvg &= tsTPF.Days.ToString & ":"
                                End If
                                If tsTPF.Hours > 9 Then
                                    strAvg &= tsTPF.Hours.ToString & ":"
                                ElseIf tsTPF.Hours > 0 Then
                                    strAvg &= "0" & tsTPF.Hours.ToString & ":"
                                Else
                                    strAvg &= "00:"
                                End If
                                If tsTPF.Minutes > 9 Then
                                    strAvg &= tsTPF.TotalMinutes.ToString & ":"
                                ElseIf tsTPF.Minutes > 0 Then
                                    strAvg &= "0" & tsTPF.Minutes.ToString & ":"
                                Else
                                    strAvg &= "00:"
                                End If
                                If tsTPF.Seconds > 9 Then
                                    strAvg &= tsTPF.Seconds.ToString
                                ElseIf tsTPF.Seconds > 0 Then
                                    strAvg &= "0" & tsTPF.Seconds.ToString
                                End If
                                Return strAvg
                            Else
                                Return String.Empty
                            End If
                        Catch ex As Exception
                            WriteError(ex.Message, Err)
                            Return ""
                        End Try
                    End Get
                End Property
#End Region
#Region "Properties"
                'project:5736 run:1 clone:616 gen:928
                Public PRCG As String = ""
                Public ReadOnly Property Project As String
                    Get
                        Dim p As String = PRCG.Replace("project:", "")
                        Return p.Substring(0, p.IndexOf(" "))
                    End Get
                End Property
                Public ReadOnly Property RCG As String
                    Get
                        Return PRCG.Substring(PRCG.IndexOf("run:"))
                    End Get
                End Property
                Public ReadOnly Property Run As String
                    Get
                        Try
                            Return RCG.Substring(4, RCG.IndexOf(" clone") - 4)
                        Catch ex As Exception
                            Return ""
                        End Try
                    End Get
                End Property
                Public ReadOnly Property Clone As String
                    Get
                        Try
                            Return RCG.Substring(RCG.IndexOf("clone:") + 6, RCG.IndexOf(" gen") - (RCG.IndexOf("clone:") + Len("clone:")))
                        Catch ex As Exception
                            Return ""
                        End Try
                    End Get
                End Property
                Public ReadOnly Property Gen As String
                    Get
                        Try
                            Return RCG.Substring(RCG.IndexOf("gen:") + 4)
                        Catch ex As Exception
                            Return ""
                        End Try
                    End Get
                End Property
                Public ID As String = ""
                Public unit As String = ""
                Public CS As String = ""
                Public WS As String = ""
                Public Slot As String = ""
                Public HW As String = ""
                Public Percentage As String = ""
                Public CoreStatus As String = ""
                Public Credit As String = ""
                Public PPD As String = ""
                Public ServerResponce As String = ""
                Public CoreSnippet As String = ""
                Public CoreVersion As String = ""
                Public CoreCompiler As String = ""
                Public Core As String = ""
                Public BoardType As String = ""
                Public Log As String = ""
                Public dtDownloaded As DateTime = #1/1/2000#
                Public dtStarted As DateTime = #1/1/2000#
                Public dtCompleted As DateTime = #1/1/2000#
                Public dtSubmitted As DateTime = #1/1/2000#
#End Region
#Region "Restarted work unit info"
                Public bHasRestarted As Boolean = False
                Public Class clsRestarted
                    Public Class clsRInfo
                        Private _CoreStatus As String = ""
                        Public ReadOnly Property CoreStatus As String
                            Get
                                Return _CoreStatus
                            End Get
                        End Property
                        Private _LastFrame As clsFrame
                        Public ReadOnly Property LastFrame As clsFrame
                            Get
                                Return _LastFrame
                            End Get
                        End Property
                        Public Sub New(ByVal CoreStatus As String, ByVal Frame As clsFrame)
                            _CoreStatus = CoreStatus : _LastFrame = Frame
                        End Sub
                    End Class
                    Private _lstrInfo As New Dictionary(Of DateTime, clsRInfo)
                    Public ReadOnly Property RestartInfo As List(Of clsRInfo)
                        Get
                            Return _lstrInfo.Values.ToList
                        End Get
                    End Property
                    Public Sub AddRestart(ByVal CoreStatus As String, ByVal Frame As clsFrame)
                        Try
                            If Not _lstrInfo.ContainsKey(Frame.FrameDT) Then
                                _lstrInfo.Add(Frame.FrameDT, New clsRInfo(CoreStatus, Frame))
                            End If
                        Catch ex As Exception
                            WriteError(ex.Message, Err)
                        End Try
                    End Sub

                End Class
                Public restartInfo As New clsRestarted
#End Region
#Region "Work unit Report"
                Public ReadOnly Property Report As String
                    Get
                        If UploadSpeed.ToUpper.Contains("INF") Then
                            Console.Write("Break here")
                        End If
                        Dim sb As New StringBuilder
                        sb.AppendLine("PRCG: " & vbTab & vbTab & PRCG)
                        sb.AppendLine("unit: " & vbTab & vbTab & unit)
                        sb.AppendLine("client: " & vbTab & vbTab & ClientName)
                        sb.AppendLine("Slot: " & vbTab & vbTab & Slot)
                        sb.AppendLine("Hardware: " & vbTab & HW)
                        sb.AppendLine("Core: " & vbTab & vbTab & Core)
                        sb.AppendLine("Corestatus: " & vbTab & CoreStatus)
                        If CoreCompiler <> "" Then sb.AppendLine("Compiler: " & vbTab & vbTab & CoreCompiler)
                        If BoardType <> "" Then sb.AppendLine("BoardType: " & vbTab & BoardType)
                        sb.AppendLine("Downloaded: " & vbTab & dtDownloaded.ToString("s"))
                        If Not TPF = String.Empty Then sb.AppendLine("Avg TPF: " & vbTab & TPF)
                        sb.AppendLine("Completed: " & vbTab & dtCompleted.ToString("s"))
                        sb.AppendLine("Submitted: " & vbTab & dtSubmitted.ToString("s"))
                        sb.AppendLine("Upload size: " & vbTab & UploadSize)
                        sb.AppendLine("Upload speed: " & vbTab & UploadSpeed)
                        sb.AppendLine("ServerResponce: " & vbTab & ServerResponce)
                        If Credit <> "" Then sb.AppendLine("Credit: " & vbTab & vbTab & Credit)
                        If PPD <> "" Then sb.AppendLine("PPD: " & vbTab & vbTab & PPD)
                        sb.AppendLine("WorkServer: " & vbTab & WS)
                        If CS <> "" And CS <> WS Then sb.AppendLine("CollectionServer: " & vbTab & CS)
                        Return sb.ToString
                    End Get
                End Property
#End Region
            End Class
            Public dWU As New Dictionary(Of String, clsWU)
            Public ReadOnly Property lstWU As List(Of clsWU)
                Get
                    Return dWU.Values.ToList
                End Get
            End Property
            Public ClientInfo As New clsClientInfo.FAHClientInfo
            Public ClientConfig As New clsClientConfig.clsConfiguration
            Public Log As String = ""
            Public File As String = ""
            'FileName is used for db storage!
            Public ReadOnly Property fileName As String
                Get
                    If File.Contains("/") Then
                        Return (File.Substring(File.LastIndexOf("/") + 1).Replace(".txt", "").Replace("-", "_"))
                    Else
                        Return (File.Substring(File.LastIndexOf("\") + 1).Replace(".txt", "").Replace("-", "_"))
                    End If
                End Get
            End Property
            Public LineCount As String = ""
            Public ReadOnly Property logDate As DateTime
                Get
                    Try
                        Return DateTime.Parse(Log.Replace("*", "").Replace("Log Started", "").Trim.Replace("-", " "))
                    Catch ex As Exception
                        Return New DateTime
                    End Try
                End Get
            End Property
        End Class
        'dLogFiles only used on ParseLogs, finalize when done to lower memory usage
        Private dLogFiles As New Dictionary(Of String, clsLogFile)
        Public ReadOnly Property lstLogFiles As List(Of clsLogFile)
            Get
                Return dLogFiles.Values.ToList
            End Get
        End Property
        Public Property ActiveWU As New List(Of clsWU)
#End Region
#Region "Parsing"
        Private Function AccreditWU(WU As clsWU) As clsWU
            Dim rWU As clsWU = WU
            Try
                'Check credit rating
                If WU.Credit = "" Then
                    If ProjectInfo.Projects.KnownProject(WU.PRCG.Substring(Len("project:"), WU.PRCG.IndexOf(" ") - Len("project:"))) And WU.CoreStatus.Contains("FINISHED_UNIT") And WU.ServerResponce.Contains("WORK_ACK") Then
                        'Only calculate if finished_unit and work_ack
                        WU.Credit = ProjectInfo.GetEffectivePPD_sqrt(WU.dtDownloaded, WU.dtSubmitted, WU.PRCG.Substring(Len("project:"), WU.PRCG.IndexOf(" ") - Len("project:"))).Credit
                    End If
                End If
                'Fix PPD
                If WU.PPD = "" And ProjectInfo.Projects.KnownProject(WU.PRCG.Substring(Len("project:"), WU.PRCG.IndexOf(" ") - Len("project:"))) And WU.ServerResponce.Contains("WORK_ACK") And WU.Credit <> "" Then
                    'If credit was given for partial results this will calculate PPD as well
                    WU.PPD = ProjectInfo.GetEffectivePPD_sqrt(WU.dtDownloaded, WU.dtSubmitted, WU.PRCG.Substring(Len("project:"), WU.PRCG.IndexOf(" ") - Len("project:"))).PPD
                ElseIf WU.PPD = "" And WU.Credit <> "" Then
                    'Calculate ppd from processing time in a day
                    Dim rv As New clsProjectInfo.sProjectPPD
                    Dim pCompletionTime As TimeSpan = WU.dtSubmitted.Subtract(WU.dtDownloaded)
                    rv.Credit = WU.Credit
                    'How many frames per 24/h
                    Dim iPPD As Double = 0
                    Dim tsDay As TimeSpan = TimeSpan.FromDays(1)
                    Do
                        If tsDay.Subtract(pCompletionTime).TotalSeconds >= 0 Then
                            iPPD += CInt(rv.Credit)
                            tsDay = tsDay.Subtract(pCompletionTime)
                        Else
                            Exit Do
                        End If
                    Loop
                    'get fraction of _tsFrame to be done in remaining seconds
                    Dim iRfraction As Double
                    If tsDay.TotalSeconds > 0 Then
                        iRfraction = tsDay.TotalSeconds / pCompletionTime.TotalSeconds
                        iPPD += iRfraction * CInt(rv.Credit)
                    End If
                    rv.PPD = CStr(Math.Round(iPPD, 2))
                    WU.PPD = rv.PPD
                    pCompletionTime = Nothing
                    rv = Nothing
                    iPPD = Nothing
                    tsDay = Nothing
                End If
            Catch ex As Exception
                WriteError(ex.Message, Err)
            End Try
            Return WU
        End Function
#End Region
    End Class
#End Region
#Region "Client collection"
    Private _Clients As New Dictionary(Of String, clsClient)
    Public ReadOnly Property Clients As List(Of clsClient)
        Get
            Return _Clients.Values.ToList
        End Get
    End Property
    Public ReadOnly Property Client(Name As String) As clsClient
        Get
            Return _Clients(Name)
        End Get
    End Property
    Public ReadOnly Property LocalClient As clsClient
        Get
            Return Clients(0)
        End Get
    End Property
    Public ReadOnly Property initialized As Boolean
        Get
            Return Clients.Count > 0
        End Get
    End Property

    Public Sub Init(Optional ByVal Name As String = "local")
        Try
            'Add local name support
            If _Clients.ContainsKey(Name) Then
                WriteLog("Attempt at creating a second client with the same name", eSeverity.Important)
            Else
                _Clients.Add(Name, New clsClient(Name, ClientConfig.Configuration.DataLocation))
            End If
        Catch ex As Exception
            WriteError(ex.Message, Err)
        End Try
    End Sub
    Public Sub AddClient(ByVal Name As String, ByVal Location As String, FCPort As String, PWD As String, FWPort As String, Optional ByVal Enabled As Boolean = True)
        Try
            If Not _Clients.ContainsKey(Name) Then
                _Clients.Add(Name, New clsClient(Name, Location))
                _Clients(Name).Enabled = Enabled
                _Clients(Name).PWD = PWD
                _Clients(Name).FWPort = FWPort
                _Clients(Name).FCPort = FCPort
            End If
        Catch ex As Exception
            WriteError(ex.Message, Err)
        End Try
    End Sub
    Public Sub SetLocation(ClientName As String, Location As String)
        'Might use this when 'migrating' clients
        _Clients(ClientName).ClientLocation = Location
        'Throw New NotImplementedException
    End Sub
    Public Sub setClientFCPort(Name As String, FCPort As String)
        _Clients(Name).FCPort = FCPort
    End Sub
    Public Sub setClientFWPort(Name As String, FWPort As String)
        _Clients(Name).FWPort = FWPort
    End Sub
    Public Sub setClientPWD(Name As String, PWD As String)
        _Clients(Name).PWD = PWD
    End Sub
    Public Sub SetClientState(ByVal Name As String, ByVal State As Boolean)
        Try
            If _Clients.ContainsKey(Name) Then
                _Clients(Name).Enabled = State
            End If
        Catch ex As Exception
            WriteError(ex.Message, Err)
        End Try
    End Sub
    Public Sub RemoveClient(ByVal Name As String)
        Try
            If _Clients.ContainsKey(Name) Then
                _Clients.Remove(Name)
            End If
        Catch ex As Exception
            WriteError(ex.Message, Err)
        End Try
    End Sub
#End Region
#Region "Combined Report"
    Public Structure sClientStatistics
        Public WU_Completed As String
        Public WU_EUE As String
        Public SuccesRate As String
        Public ComputationTime As String
        Public TotalCredit As String
    End Structure
    Public ReadOnly Property Statistics As sClientStatistics
        Get
            Dim rV As New sClientStatistics
            Try
                Dim iWU_total As Int32 = 0
                Dim iWU_EUE As Int32 = 0
                Dim tsProcessing As New TimeSpan
                Dim tsWaitingToUpload As New TimeSpan
                Dim iTotalCredit As Int32 = 0
                For Each Client As clsClient In Me.Clients
                    For Each lSec As clsClient.clsLogFile In Client.lstLogFiles
                        For Each lWU As clsClient.clsLogFile.clsWU In lSec.lstWU
                            iWU_total += 1
                            'Debug.WriteLine(lWU.PRCG)
                            If lWU.CoreStatus <> "" Then
                                If Not lWU.CoreStatus.Contains("(100)") And Not lWU.CoreStatus.Contains("(100 = 0x64)") Then iWU_EUE += 1
                                ' WaitingToUpload is not incrementd with unit's which don't have any frames ( though, should it be counted for partial results which do generate some credit.. )
                                If lWU.Frames.Count > 0 Then
                                    tsProcessing = tsProcessing.Add(lWU.Frames(lWU.Frames.Count - 1).FrameDT - lWU.Frames(0).FrameDT)
                                    tsWaitingToUpload = tsWaitingToUpload.Add(lWU.dtSubmitted.Subtract(lWU.Frames(lWU.Frames.Count - 1).FrameDT))
                                End If
                                If lWU.dtSubmitted <> #1/1/2000# And lWU.ServerResponce.Contains("(400)") Then
                                    If lWU.Credit = "" Then
                                        If ProjectInfo.Projects.KnownProject(lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))) Then
                                            iTotalCredit += CInt(ProjectInfo.GetEffectivePPD_sqrt(lWU.dtDownloaded, lWU.dtSubmitted, lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))).Credit)
                                        End If
                                    Else
                                        'Code duplication :(
                                        Dim tsP As TimeSpan = lWU.dtSubmitted.Subtract(lWU.dtDownloaded)
                                        Dim iPworth As Integer = CInt(lWU.Credit)
                                        Dim iPPD As Double = 0
                                        Dim tsDay As TimeSpan = TimeSpan.FromDays(1)
                                        Do
                                            If tsDay.Subtract(tsP).TotalSeconds >= 0 Then
                                                iPPD += iPworth
                                                tsDay = tsDay.Subtract(tsP)
                                            Else
                                                Exit Do
                                            End If
                                        Loop
                                        'get fraction of _tsFrame to be done in remaining seconds
                                        Dim iRfraction As Double
                                        If tsDay.TotalSeconds > 0 Then
                                            iRfraction = tsDay.TotalSeconds / tsP.TotalSeconds
                                            iPPD += iRfraction * iPworth
                                        End If
                                        iTotalCredit = CInt(iTotalCredit + Math.Round(iPPD, 2))
                                    End If
                                End If
                            End If
                        Next
                    Next
                Next
                rV.WU_Completed = iWU_total.ToString
                rV.WU_EUE = iWU_EUE.ToString
                rV.SuccesRate = 100 - (iWU_EUE / (iWU_total / 100)) & "%"
                rV.ComputationTime = tsProcessing.ToString
                rV.TotalCredit = iTotalCredit.ToString
            Catch ex As Exception
                WriteError(ex.Message, Err)
            End Try
            Return rV
        End Get
    End Property
    Public ReadOnly Property SystemStatistics As String
        Get
            Dim sb As New StringBuilder
            Try
                Dim iWU_total As Int32 = 0
                Dim iWU_EUE As Int32 = 0
                Dim tsProcessing As New TimeSpan
                Dim iTotalCredit As Int32 = 0
                For Each Client As clsClient In Me.Clients
                    For Each lSec As clsClient.clsLogFile In Client.lstLogFiles
                        For Each lWU As clsClient.clsLogFile.clsWU In lSec.lstWU
                            iWU_total += 1
                            'Debug.WriteLine(lWU.PRCG)
                            If lWU.CoreStatus <> "" Then
                                If Not lWU.CoreStatus.Contains("(100)") And Not lWU.CoreStatus.Contains("(100 = 0x64)") Then iWU_EUE += 1
                                ' WaitingToUpload is not incrementd with unit's which don't have any frames ( though, should it be counted for partial results which do generate some credit.. )
                                If lWU.Frames.Count > 0 Then
                                    tsProcessing = tsProcessing.Add(lWU.Frames(lWU.Frames.Count - 1).FrameDT - lWU.Frames(0).FrameDT)
                                End If
                                If lWU.dtSubmitted <> #1/1/2000# And lWU.ServerResponce.Contains("(400)") Then
                                    If lWU.Credit = "" Then
                                        If ProjectInfo.Projects.KnownProject(lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))) Then
                                            iTotalCredit += CInt(ProjectInfo.GetEffectivePPD_sqrt(lWU.dtDownloaded, lWU.dtSubmitted, lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))).Credit)
                                        End If
                                    Else
                                        'Code duplication :(
                                        Dim tsP As TimeSpan = lWU.dtSubmitted.Subtract(lWU.dtDownloaded)
                                        Dim iPworth As Integer = CInt(lWU.Credit)
                                        Dim iPPD As Double = 0
                                        Dim tsDay As TimeSpan = TimeSpan.FromDays(1)
                                        Do
                                            If tsDay.Subtract(tsP).TotalSeconds >= 0 Then
                                                iPPD += iPworth
                                                tsDay = tsDay.Subtract(tsP)
                                            Else
                                                Exit Do
                                            End If
                                        Loop
                                        'get fraction of _tsFrame to be done in remaining seconds
                                        Dim iRfraction As Double
                                        If tsDay.TotalSeconds > 0 Then
                                            iRfraction = tsDay.TotalSeconds / tsP.TotalSeconds
                                            iPPD += iRfraction * iPworth
                                        End If
                                        iTotalCredit = CInt(iTotalCredit + Math.Round(iPPD, 2))
                                    End If
                                End If
                            End If
                        Next
                    Next
                Next
                sb.AppendLine("Total work units: " & vbTab & iWU_total.ToString)
                sb.AppendLine("Early Unit Ends: " & vbTab & iWU_EUE.ToString)
                sb.AppendLine("Succes rate: " & vbTab & vbTab & (100 - (iWU_EUE / (iWU_total / 100))) & "%")
                sb.AppendLine("Total processing time: " & vbTab & tsProcessing.ToString)
                sb.AppendLine("Total credit: " & vbTab & vbTab & iTotalCredit.ToString)
            Catch ex As Exception
                sb.AppendLine("ERROR: " & ex.Message & " - " & ex.StackTrace.ToString & ex.TargetSite.ToString)
            End Try
            Return sb.ToString
        End Get
    End Property
#End Region
#Region "Functions"
    Shared startLog As New LogStartObject
    Public Function ParseLogs(Optional ShowBussy As Boolean = False, Optional ParentForm As Form = Nothing) As Boolean
        Try
            If ShowBussy Then
                Bussy.ShowForm("Parsing logs... please wait")
            End If
            For Each Client As clsClient In Clients
                'Check files
                startLog.clear()
                Dim nFiles As New List(Of String)
                Dim lFiles As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = My.Computer.FileSystem.GetFiles(Client.ClientLocation & "\Logs\", FileIO.SearchOption.SearchTopLevelOnly, "log*.txt")
                For Each File As String In lFiles
                    If Not sqdata.IsLogStored(Client.ClientName, File.Substring(File.LastIndexOf("\") + 1)) Then
                        nFiles.Add(File)
                    End If
                Next
                With startLog
                    .ClientName = Client.ClientName
                    .ShowUI = ShowBussy
                    .Files = nFiles
                    .asThread = True
                End With
                'ParseLog(startLog)
                Dim pThread As New Threading.Thread(AddressOf ParseLog)
                pThread.Start({startLog})
                While pThread.IsAlive
                    Application.DoEvents()
                    'Threading.Thread.Yield()
                End While
                'Store/Update/Remove
                WriteDebug("Join finished")
            Next
            If ShowBussy And Bussy.IsFormVisible Then
                Bussy.CloseForm()
            End If
            Return True
        Catch ex As Exception
            WriteError(ex.Message, Err)
            Return False
        End Try
    End Function
#End Region
    <MTAThread()>
    Public Sub ParseLog(start As Object)
        Try
            'WriteDebug("Started parselog thread at " & DateTime.Now.ToLongTimeString)
            Dim lStart As LogStartObject = clsClients.startLog
            'Declare combined log object
            Dim comLog As New List(Of String)
            Try
                Dim nFiles As List(Of String) = lStart.Files
                Dim iFile As Int32 = 1 'Index of log file 
                Dim iLog As Int32 = 0 'Index of current line in log
                Dim iSkipLog As Int32 = -1 'Next line with unit request
                'sqData.StartTransaction()
                'Main file loop
                'WriteDebug("Parsing client " & lStart.ClientName)
                If lStart.ShowUI Then
                    If Not Bussy.IsFormVisible Then
                        Bussy.ShowForm("Parsing logs for " & lStart.ClientName)
                    Else
                        Bussy.SetMessage("Parsing logs for " & lStart.ClientName)
                    End If
                Else
                    'Set ui message when bussy is visible?
                    'If Bussy.IsFormVisible Then
                    '    Bussy.SetMessage("Parsing logs for " & ClientName)
                    'End If
                    '
                    'No, add support for background update's displaying progress on a statusbar or something
                End If
                Dim iIndex As Int32 = 0
                Dim iStored As Int32 = 0
                Dim iActive As Int32 = 0
                Do
                    Dim nLOG As New clsLogFile(lStart.ClientName)
                    nLOG.File = nFiles(iFile - 1)
                    'Check and verify
                    'WriteDebug("Processing " & nLOG.fileName)
                    Try
                        'If lStart.FinishedLogs.Contains(nLOG) Then
                        '    GoTo SkipFile
                        'End If
                        'If sqdata.IsLogStored(lStart.ClientName, nLOG.fileName) Then
                        '    'Change this to retrieve active wu's?
                        '    'WriteDebug("-Log is stored, skipping")
                        '    'Dismiss line count since the log is ignored?
                        '    GoTo SkipFile
                        '    'Read logsection back from sqdata for linecount 
                        '    'nLOG = sqData.StoredLog(ClientName, nLOG.fileName)
                        '    'Add the log section 
                        '    'If Not dLogFiles.ContainsKey(nLOG.Log.Replace("*", "").Trim) Then
                        '    '    dLogFiles.Add(nLOG.Log.Replace("*", "").Trim, nLOG)
                        '    'End If
                        '    ''WriteDebug("-Skipping to next file")
                        '    'GoTo SkipFile
                        'End If
                    Catch ex As Exception
                        WriteLog("An error has occured, details below", eSeverity.Important)
                        WriteError(ex.Message, Err)
                    End Try
                    'Get file content
                    Dim lText As String = ""
                    Try
                        lText = My.Computer.FileSystem.ReadAllText(nFiles(iFile - 1))
                    Catch ex As Exception
                        Dim fStream As FileStream = New FileStream(nFiles(iFile - 1), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024, System.IO.FileOptions.Asynchronous)
                        Dim fRead As StreamReader = New StreamReader(fStream)
                        lText = fRead.ReadToEnd
                        fRead.Dispose()
                        fStream.Dispose()
                    End Try
                    If lText.IndexOf(ChrW(10)) = lText.IndexOf(GetChar(Environment.NewLine, 1)) + 1 Then
                        WriteLog("Stripping log of chrw(10)", eSeverity.Debug)
                        lText = lText.Replace(ChrW(10), "")
                    End If
                    Dim lLines() = lText.Split(GetChar(Environment.NewLine, 1))
                    Dim iAddDays As Int32 = 0
                    nLOG.LineCount = lLines.Count.ToString
                    nLOG.Log = lLines(0)
                    comLog.AddRange(lLines)
                    'Fill client info
                    If lText.Contains("********************** Folding@home Client *************************") And lText.Contains("********************************************************************") Then
                        Dim strInfo As String = lText.Substring(lText.IndexOf("********************** Folding@home Client *************************"), lText.LastIndexOf("********************************************************************") - lText.IndexOf("********************** Folding@home Client *************************"))
                        Dim sb As New StringBuilder
                        For Each Line As String In strInfo.Split(GetChar(Environment.NewLine, 1))
                            Try
                                If Not Line.IndexOf(":") = -1 Then
                                    sb.AppendLine(Line.Substring(9).Trim)
                                Else
                                    sb.AppendLine(Line)
                                End If
                            Catch ex As Exception

                            End Try
                        Next
                        strInfo = sb.ToString
                        lStart.ClientInfo = New clsClientInfo
                        lStart.ClientInfo.Info = lStart.ClientInfo.Info.ParseString(strInfo)
                        'If Not sqdata.HasClientInfo(lStart.ClientName, nLOG.logDate) Then
                        lStart.dClientInfo.Add(nLOG.logDate, lStart.ClientInfo)
                        'End If
                    End If
                    'Finds original <config> at client startup
                    If lText.ToUpper.Contains("<CONFIG>") AndAlso lText.ToUpper.Contains("</CONFIG>") Then
                        Dim indexStart As Int32 = lText.ToUpper.IndexOf("<CONFIG>")
                        Dim indexEnd As Int32 = lText.ToUpper.IndexOf("</CONFIG>") + 9 'len </config>
                        Dim iLen As Int32 = indexEnd - indexStart
                        Dim strConfig As String = lText.Substring(indexStart, iLen)
                        Dim sb As New StringBuilder
                        For Each Line As String In strConfig.Split(GetChar(Environment.NewLine, 1))
                            Try
                                While Not Line.IndexOf(":") = -1
                                    Line = Line.Substring(Line.IndexOf(":") + 1)
                                End While
                                sb.AppendLine(Line)
                            Catch ex As Exception
                                WriteError(ex.Message, Err)
                            End Try
                        Next
                        strConfig = sb.ToString
                        lStart.ClientConfig = New clsClientConfig
                        If Not lStart.dClientConfig.ContainsKey(strConfig & "##" & nLOG.logDate.ToString("s")) Then
                            If lStart.ClientConfig.Configuration.ReadString(strConfig) Then
                                lStart.ClientConfig.Configuration.ConfigurationDT = nLOG.logDate
                                lStart.dClientConfig.Add(strConfig & "##" & nLOG.logDate.ToString("s"), lStart.ClientConfig)
                            Else
                                'WriteDebug("Failed to process the client configuration options")
                            End If
                        End If
                    End If

                    Try
                        'Main line loop
                        iLog = 0
                        Do
                            Dim Line As String = ""
                            Line = lLines(iLog).ToUpper
                            'If Line.Contains("unit:0x3cf713374eefdbea03c9027000021665".ToUpper) Then
                            '    MsgBox("Break")
                            'End If
                            If iLog - 1 > 0 And Line.Length > 2 AndAlso lLines(iLog - 1).Length > 2 Then
                                Try
                                    If CInt(lLines(iLog - 1).Replace(ChrW(34), "").Substring(0, 2)) > CInt(lLines(iLog).Replace(ChrW(34), "").Substring(0, 2)) Then
                                        iAddDays += 1
                                    End If
                                Catch ex As Exception : End Try
                            End If
                            'Check for new <config> 
                            If lLines(iLog).ToUpper.Contains("<CONFIG>") Then
                                Dim iEnd As Int32 = -1
                                For xInt As Int32 = iLog To CInt(nLOG.LineCount) - 1
                                    If lLines(xInt).ToUpper.Contains("</CONFIG>") Then
                                        iEnd = xInt
                                        Exit For
                                    End If
                                Next
                                If iEnd <> -1 Then
                                    Dim dtNConfig As DateTime = nLOG.logDate.Date.AddDays(iAddDays).Add(TimeSpan.Parse(lLines(iEnd).Substring(0, 8)))
                                    'If Not sqdata.HasClientConfig(lStart.ClientName, dtNConfig) Then
                                    '    Dim strB As New StringBuilder
                                    '    For xInt As Int32 = iLog To iEnd
                                    '        strB.Append(lLines(xInt).Substring(9))
                                    '    Next
                                    '    If Not lStart.ClientConfig.Configuration.ReadString(strB.ToString) Then
                                    '        WriteLog("Log parser hit a snare parsing a <config> </config> section", eSeverity.Important)
                                    '    Else
                                    '        If Not lStart.dClientConfig.ContainsKey(dtNConfig) Then
                                    '            lStart.dClientConfig.Add(dtNConfig, lStart.ClientConfig)
                                    '        End If
                                    '    End If
                                    'End If
                                    Dim strB As New StringBuilder
                                    For xInt As Int32 = iLog To iEnd
                                        strB.Append(lLines(xInt).Substring(9))
                                    Next
                                    If Not lStart.ClientConfig.Configuration.ReadString(strB.ToString) Then
                                        WriteLog("Log parser hit a snare parsing a <config> </config> section", eSeverity.Important)
                                    Else
                                        If Not sqdata.HasClientConfig(lStart.ClientName, strB.ToString, dtNConfig) Then
                                            If Not lStart.dClientConfig.ContainsKey(strB.ToString & "##" & dtNConfig.ToString("s")) Then
                                                lStart.ClientConfig.Configuration.ConfigurationDT = dtNConfig
                                                lStart.dClientConfig.Add(strB.ToString & "##" & dtNConfig.ToString("s"), lStart.ClientConfig)
                                            End If
                                        End If
                                    End If
                                    iSkipLog = iEnd
                                    GoTo NewLine
                                Else
                                    WriteLog("Parsing loop missed an </config>!", eSeverity.Critical)
                                End If
                            End If
                            'With the new log content, using Line.IndexOf("RECIEVED UNIT: ", 0, StringComparison.OrdinalIgnoreCase) will speed things up
                            If Line.Contains("RECEIVED UNIT") Then 'Received Unit
                                'Start parsing all info for this work unit
                                Dim nWU As New clsWU
                                nWU.lineIndex = iLog
                                nWU.ClientName = lStart.ClientName
                                nWU.Log = nLOG.Log
                                nWU.FileName = nLOG.File
                                nWU.LogDT = nLOG.logDate
                                nWU.ID = lLines(iLog).Substring(Line.IndexOf("ID:") + 3, Line.IndexOf("STATE:") - (Line.IndexOf("ID:") + 3)).Trim
                                nWU.unit = lLines(iLog).Substring(Line.LastIndexOf("UNIT:") + 5).Trim.ToLower
                                nWU.PRCG = lLines(iLog).Substring(Line.IndexOf("PROJECT:"), Line.IndexOf("CORE:") - (Line.IndexOf("PROJECT:"))).Trim
                                nWU.Core = lLines(iLog).Substring(Line.IndexOf("CORE:") + 5, 4).Trim
                                'fill wu info, scan lines upwards for 'Download complete'
                                'Add another iAddDays variable to catch recieved happening at 00:01 and download complete at 23:59?
                                Dim iRDays As Int32 = 0
                                For xInt As Int32 = iLog To 0 Step -1
                                    If xInt > 0 AndAlso lLines(xInt).Length > 2 AndAlso lLines(xInt - 1).Length > 2 Then
                                        Try
                                            If CInt(lLines(xInt).Replace(ChrW(34), "").Substring(0, 2)) > CInt(lLines(xInt - 1).Replace(ChrW(34), "").Substring(0, 2)) Then
                                                iRDays += 1
                                                'WriteDebug("Removed a day! " & lLines(xInt).Substring(0, 8) & " - " & lLines(xInt).Substring(0, 8))
                                            End If
                                        Catch ex As Exception : End Try
                                    End If
                                    If lLines(xInt).ToUpper.Contains("DOWNLOAD COMPLETE") And nWU.Slot = "" Then
                                        nWU.Slot = lLines(xInt).Substring(lLines(xInt).ToLower.IndexOf("slot ") + Len("slot "), 2)
                                        nWU.dtDownloaded = nLOG.logDate.Date.AddDays(iAddDays - iRDays).Add(TimeSpan.Parse(lLines(xInt).Substring(0, 8)))
                                        'WriteDebug("Found Downloaded timestamp: " & nWU.dtDownloaded.ToString("s"))
                                        'check db for existing unit
                                        'If sqdata.HasWorkUnit(lStart.ClientName, nWU.Slot, nWU.ID) Then
                                        '    'WriteDebug(nWU.PRCG & "-" & nWU.unit & " already known, skipping work unit")
                                        '    GoTo NewLine
                                        'End If
                                    ElseIf lLines(xInt).ToUpper.Contains("REQUESTING NEW WORK UNIT FOR SLOT") Then
                                        If lLines(xInt).Contains(Chr(34)) Then
                                            nWU.HW = lLines(xInt).Substring(lLines(xInt).IndexOf(ChrW(34)) + 1, lLines(xInt).LastIndexOf(ChrW(34)) - lLines(xInt).IndexOf(ChrW(34)) - 1)
                                            'WriteDebug("Hardware for work unit detected: " & nWU.HW)
                                        Else
                                            If lLines(xInt).ToUpper.Contains("READY") Then
                                                nWU.HW = lLines(xInt).Substring(lLines(xInt).ToUpper.IndexOf("READY") + 6, lLines(xInt).ToUpper.IndexOf("FROM") - (lLines(xInt).ToUpper.IndexOf("READY") + 8))
                                                'WriteDebug("Hardware for work unit detected: " & nWU.HW)
                                            ElseIf lLines(xInt).ToUpper.Contains("PAUSED") Then
                                                nWU.HW = lLines(xInt).Substring(lLines(xInt).ToUpper.IndexOf("PAUSED") + 7, lLines(xInt).ToUpper.IndexOf("FROM") - (lLines(xInt).ToUpper.IndexOf("PAUSED") + 8))
                                                'WriteDebug("Hardware for work unit detected: " & nWU.HW)
                                            ElseIf lLines(xInt).ToUpper.Contains("RUNNING") Then
                                                nWU.HW = lLines(xInt).Substring(lLines(xInt).ToUpper.IndexOf("RUNNING") + 8, lLines(xInt).ToUpper.IndexOf("FROM") - (lLines(xInt).ToUpper.IndexOf("RUNNING") + 8))
                                                'WriteDebug("Hardware for work unit detected: " & nWU.HW)
                                            End If
                                        End If
                                    ElseIf nWU.WS = "" AndAlso lLines(xInt).ToUpper.Contains("ASSIGNED TO WORK SERVER ") Then '"Assigned to work server "
                                        nWU.WS = lLines(xInt).ToUpper.Substring(lLines(xInt).ToUpper.IndexOf("ASSIGNED TO WORK SERVER ") + Len("ASSIGNED TO WORK SERVER ")).Trim
                                        'WriteDebug("Work server detected : " & nWU.WS)
                                        Exit For
                                    End If
                                Next
                                If Not nLOG.dWU.ContainsKey(nWU.unit & "-" & nWU.dtDownloaded.ToString("s")) Then
                                    If Not sqdata.HasWorkUnit(nWU.ClientName, nWU.Slot, nWU.unit, nWU.dtDownloaded) Then
                                        'WriteDebug("Found work unit: " & nWU.PRCG & " - " & nWU.unit & " in " & nLOG.fileName)
                                        iIndex += 1
                                        If lStart.ShowUI Then
                                            Bussy.SetMessage("Parsing logs for " & lStart.ClientName & Environment.NewLine & "Found " & iIndex & " work unit indexes")
                                        End If
                                        'WriteDebug("Adding work unit to section collection :" & nWU.PRCG & " - " & nWU.unit)
                                        nLOG.dWU.Add(nWU.unit & "-" & nWU.dtDownloaded.ToString("s"), nWU)
                                    End If
                                End If
                            End If
NewLine:
                            Application.DoEvents()
                            'Increase line pointer
                            'iLog += 1
                            If iSkipLog = -1 Then
                                iLog += 1
                            Else
                                'DebugOut.WriteLog("Skipping to line: " & iSkipLog)
                                iLog = iSkipLog
                                iSkipLog = -1
                            End If
                            'Application.DoEvents()
                            '/Main line loop
                        Loop While iLog < lLines.Count - 1
                    Catch ex As Exception
                        WriteError(ex.Message, Err)
                        Err.Clear()
                    End Try
SkipFile:
                    Try
                        'Copy log section
                        ''Add the log section 
                        If Not lStart.dLogFiles.ContainsKey(nLOG.Log.Replace("*", "").Trim) Then
                            lStart.dLogFiles.Add(nLOG.Log.Replace("*", "").Trim, nLOG)
                        End If
                        'Increase file pointer
                        iFile += 1
                        '/Main file loop
                    Catch ex As Exception
                        WriteError(ex.Message, Err)
                    End Try
                Loop While iFile <= nFiles.Count

                'Can add function here to remove logfiles from the database which are now cycled/don't exist anymore

                ' Parse unit's
                Dim iLogStartIndex As Int32 = 0
                For iSection As Int32 = 0 To lStart.dLogFiles.Count - 1
                    Dim currentSection As clsLogFile = lStart.lLogFiles(iSection)
                    'Get startindex for comLog
                    If iSection > 0 Then
                        If Not lStart.lLogFiles(iSection - 1).LineCount = "" Then
                            iLogStartIndex += CInt(lStart.lLogFiles(iSection - 1).LineCount)
                        End If
                    End If
                    ''WriteDebug("Processing " & currentSection.fileName)
                    If currentSection.AllDone Then
                        ''WriteDebug("Skipping log section " & currentSection.fileName & " WorkUnits:" & currentSection.dWU.Values.Count)
                        GoTo NextSection
                    End If
                    For Each nWU As clsWU In currentSection.lstWU
                        If sqdata.HasWorkUnit(lStart.ClientName, nWU.Slot, nWU.unit, nWU.dtDownloaded) Then
                            'WriteDebug("Skip skipping")
                            'GoTo NextWU
                        End If
                        'WriteDebug("--Starting to parse " & nWU.PRCG & " - Slot:" & nWU.Slot & " ID:" & nWU.ID)
                        'Enumerate work units recieved in this log 
                        Dim iAddDays As Int32 = 0, dtStart As DateTime = nWU.dtDownloaded
                        Dim xInt As Int32 = nWU.lineIndex + iLogStartIndex
                        '08:11:34:Received Unit: id:01 state:DOWNLOAD error:OK project:7610 run:525 clone:0 gen:30 core:0xa4 unit:0x00000025664f2dd04de6d4941999a3d7
                        If Not (comLog(xInt).ToUpper.Contains("RECEIVED UNIT: ID:" & nWU.ID.ToUpper) Or Not comLog(xInt).ToUpper.Contains(nWU.PRCG.ToString.ToUpper)) Then
                            'WriteDebug("--Wrong starting index!!")
                        End If
                        Do
                            'Declare iSkip for skipping to a line
                            Dim iSkip As Int32 = -1
                            'Check for iAddDays
                            Try
                                If xInt - 1 > 0 And comLog(xInt).Length > 2 AndAlso comLog(xInt - 1).Length > 2 Then
                                    Try
                                        If CInt(comLog(xInt - 1).Replace(ChrW(34), "").Substring(0, 2)) > CInt(comLog(xInt).Replace(ChrW(34), "").Substring(0, 2)) Then
                                            iAddDays += 1
                                        End If
                                    Catch ex As Exception : End Try
                                End If
                            Catch ex As Exception
                                'WriteDebug("check iAddDays: " & ex.Message)
                            End Try
                            'Check for new " Log Started "
                            If comLog(xInt).ToUpper.Contains("LOG STARTED") Then
                                Try
                                    'WriteDebug("Setting new log started value")
                                    'Set new starting datetime, reset iAddDays
                                    dtStart = DateTime.Parse(comLog(xInt).Replace("*", "").Replace("Log Started", "").Trim.Replace("-", " "))
                                    iAddDays = 0
                                    'WriteDebug("Setting new log start date:" & dtStart.ToString)
                                Catch ex As Exception
                                    WriteError(ex.Message, Err)
                                End Try
                            ElseIf comLog(xInt).ToUpper.Contains("WARNING: UNIT " & nWU.ID) AndAlso comLog(xInt).Contains("MIGRATING TO SLOT") Then
                                'Migrate to other slot - continue parsing 
                                'WriteDebug("Work unit has migrated to a new slot, change ID and continue")
                                nWU.Slot = comLog(xInt).Substring(comLog(xInt).IndexOf("migrating to Slot ") + Len("migrating to Slot "))
                            ElseIf nWU.dtStarted = #1/1/2000# AndAlso comLog(xInt).ToUpper.Contains(("STARTING UNIT " & nWU.ID).ToString) Then
                                nWU.dtStarted = dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(xInt).Substring(0, 8)))
                                'WriteDebug("Setting dtStarted:" & nWU.dtStarted.ToString)
                            ElseIf nWU.CoreVersion = "" AndAlso comLog(xInt).ToUpper.Contains("UNIT " & nWU.ID & ":VERSION ") Then
                                nWU.CoreVersion = comLog(xInt).Substring(comLog(xInt).ToUpper.IndexOf("VERSION ") + 8).Trim
                                'WriteDebug("Setting new core version:" & nWU.CoreVersion)
                            ElseIf nWU.CoreCompiler = "" AndAlso comLog(xInt).ToUpper.Contains("UNIT " & nWU.ID & ":COMPILER ") Then
                                nWU.CoreCompiler = comLog(xInt).Substring(comLog(xInt).ToUpper.IndexOf("COMPILER ") + 11).Trim
                                'WriteDebug("Setting new core compiler:" & nWU.CoreCompiler)
                            ElseIf nWU.BoardType = "" AndAlso comLog(xInt).ToUpper.Contains("UNIT") AndAlso comLog(xInt).ToUpper.Contains("BOARD TYPE:") Then
                                nWU.BoardType = comLog(xInt).Substring(comLog(xInt).ToUpper.IndexOf("BOARD TYPE:") + 11).Trim
                                'WriteDebug("Setting new board type:" & nWU.BoardType)
                            ElseIf comLog(xInt).Contains("Unit " & nWU.ID & ":") And comLog(xInt).Contains("%") Then
                                Try
                                    For xIP As Int32 = comLog(xInt).IndexOf("%") To 1 Step -1
                                        If comLog(xInt).Substring(xIP, 1) = " " Or comLog(xInt).Substring(xIP, 1) = "(" Then
                                            nWU.Percentage = comLog(xInt).Substring(xIP, comLog(xInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim
                                            nWU.AddFrame(comLog(xInt), dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(xInt).Substring(0, 8))))
                                            'WriteDebug("Setting new progress:" & nWU.Percentage & " at:" & dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(xInt).Substring(0, 8))))
                                            Exit For
                                        End If
                                        '/xIP index of percentage parsing
                                    Next
                                Catch ex As Exception
                                    'WriteDebug("An exception has occured trying to set a new checkpoint value for " & nWU.PRCG & " - " & nWU.unit)
                                    'WriteDebug("-Line: " & comLog(xInt))
                                    WriteError(ex.Message, Err)
                                End Try
                            ElseIf comLog(xInt).ToUpper.Contains("WARNING: UNIT " & nWU.ID) AndAlso comLog(xInt).Contains("DUMPING") Then
                                'WriteDebug("Dumping unit detected")
                                nWU.CoreStatus = "dumped" 'comLog(xInt).Substring(9)
                                nWU.dtCompleted = dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(xInt).Substring(0, 8)))
                                Dim iStart As Int32 = -1
                                'iStart
                                For zInt As Int32 = xInt To xInt - 50 Step -1
                                    If zInt = 0 Then
                                        'WriteDebug("Dump exited without start index")
                                        iStart = 0
                                        Exit For
                                    End If
                                    If (comLog(zInt).ToUpper.Contains("UNIT " & nWU.ID & ":") And comLog(zInt).Contains("%")) Then
                                        'WriteDebug("Dump exited due to last frame found")
                                        iStart = zInt
                                        Exit For
                                    ElseIf comLog(zInt).ToUpper.Contains("UNIT " & nWU.ID & ":ENTERING") Then
                                        'WriteDebug("Dump exited due to unit start detection")
                                        iStart = zInt
                                        Exit For
                                    End If
                                Next
                                If iStart = -1 Then
                                    If xInt > 25 Then
                                        iStart = xInt - 25
                                        'WriteDebug("Setting istart to xInt - 25")
                                    Else
                                        iStart = 0
                                        'WriteDebug("Setting iStart to 0")
                                    End If
                                End If
                                'iEnd 
                                Dim iEnd As Int32 = -1
                                Dim iAddDays2 As Int32 = iAddDays
                                For yInt As Int32 = xInt To comLog.Count - 1
                                    Try
                                        If CInt(comLog(yInt - 1).Substring(0, 2)) > CInt(comLog(yInt).Substring(0, 2)) Then
                                            iAddDays2 += 1
                                            'WriteDebug("Added a day to iAddDays2, current value:" & iAddDays2 & " - current date:" & dtStart.Date.AddDays(iAddDays2).Add(TimeSpan.Parse(comLog(yInt).Substring(0, 8))))
                                        End If
                                    Catch ex As Exception : End Try
                                    If comLog(yInt).ToUpper.Contains("UNIT " & nWU.ID & ": UPLOADING ") Then
                                        Try
                                            nWU.dtStartUpload = dtStart.Date.AddDays(iAddDays2).Add(TimeSpan.Parse(comLog(yInt).Substring(0, 8)))
                                            nWU.UploadSize = comLog(yInt).Substring(comLog(yInt).ToUpper.IndexOf("UNIT " & nWU.ID & ": UPLOADING ") + Len("Unit " & nWU.ID & ": Uploading "))
                                            If nWU.UploadSize.IndexOf(" ") > 0 Then
                                                nWU.UploadSize = nWU.UploadSize.Substring(0, nWU.UploadSize.IndexOf(" "))
                                            End If
                                            If comLog(yInt).IndexOf(" to ") > 0 Then
                                                nWU.CS = comLog(yInt).Substring(comLog(yInt).IndexOf(" to ") + 4)
                                            End If
                                            'WriteDebug("Detected upload, upload size:" & nWU.UploadSize & " CS:" & nWU.CS)
                                        Catch ex As Exception
                                            'WriteDebug("An error has occured setting the upload event of " & nWU.PRCG & " - " & nWU.unit)
                                            'WriteDebug("-Line: " & comLog(yInt))
                                            WriteError(ex.Message, Err)
                                        End Try
                                    ElseIf comLog(yInt).ToUpper.Contains("UNIT " & nWU.ID & ": UPLOAD COMPLETE") Then
                                        nWU.dtSubmitted = dtStart.Date.AddDays(iAddDays2).Add(TimeSpan.Parse(comLog(yInt).Substring(0, 8)))
                                        'WriteDebug("Detected succesfull submission at " & nWU.dtSubmitted.ToString)
                                        'For zInt As Int32 = yInt To comLog.Count - 1
                                        '    'WriteDebug("Looking for server responces")
                                        '    If comLog(zInt).Contains("Server responded ") Then
                                        '        nWU.ServerResponce = comLog(zInt).Substring(comLog(zInt).IndexOf("Server responded ") + Len("Server responded "))
                                        '        'WriteDebug("Response found:" & nWU.ServerResponce & ", end of log snippet set and exiting for-next")
                                        '        iEnd = zInt
                                        '        'Exit For
                                        '    ElseIf zInt > yInt + 50 Then
                                        '        'WriteDebug("Server response is taking a long time :(")
                                        '    ElseIf zInt = comLog.Count - 1 Then
                                        '        'WriteDebug("Couldn't determin server response!")
                                        '    End If
                                        '    '/zInt for serverResponse
                                        'Next
                                    ElseIf comLog(yInt).ToUpper.Contains("SERVER RESPONDED ") Then
                                        nWU.ServerResponce = comLog(yInt).Substring(comLog(yInt).ToUpper.IndexOf("SERVER RESPONDED ") + Len("Server responded "))
                                        'WriteDebug("Response found:" & nWU.ServerResponce & ", end of log snippet set and exiting for-next")
                                        iEnd = yInt
                                    ElseIf comLog(yInt).ToUpper.Contains("FINAL CREDIT ESTIMATE") Then
                                        nWU.Credit = CInt(comLog(yInt).Trim(Chr(10)).Substring(32).ToUpper.Replace(" POINTS", "").Trim).ToString
                                        'WriteDebug("Server reported credit estimate: " & nWU.Credit)
                                    ElseIf comLog(yInt).ToUpper.Contains("CLEANING UP UNIT") AndAlso comLog(yInt).Contains(nWU.ID) Then
                                        'This should not happen before any upload, server responce and credit estimate has been found
                                        iEnd = yInt
                                        'WriteDebug("Cleaning up detected, accrediting wu, setting iEnd and exiting for-next")
                                        nWU = AccreditWorkunit(nWU)
                                        GoTo CreateSnippet2
                                    ElseIf comLog(yInt).ToUpper.Contains("STARTING UNIT " & nWU.ID) Then
                                        'WriteDebug("Unit seems to be restarted")
                                        nWU.bHasRestarted = True
                                        If nWU.Frames.Count >= 1 Then
                                            nWU.restartInfo.AddRestart(nWU.CoreStatus, nWU.Frames(nWU.Frames.Count - 1))
                                        Else
                                            'Check!
                                            nWU.restartInfo.AddRestart(nWU.CoreStatus, New clsWU.clsFrame("06:29:02:Unit 18:Completed INVALID out of INVALID steps  (0%)", nWU.dtDownloaded))
                                        End If
                                        'Check to clear frames
                                        For zInt As Int32 = yInt To comLog.Count - 1
                                            If comLog(zInt).ToUpper.Contains("UNIT") AndAlso comLog(yInt).Contains(nWU.ID) AndAlso comLog(yInt).ToUpper.Contains("PROJECT") Then
                                                If Not comLog(zInt).ToUpper.Contains(nWU.Project & " (RUN " & nWU.Run & ", CLONE " & nWU.Clone & ", GEN " & nWU.Gen & ")") Then
                                                    'WriteDebug("Unit which has been started is not identical even if it has the same ID!")
                                                    'WriteLog("WARNING: Unit " & nWU.unit & " parsing loop hit a snare!")
                                                End If
                                            ElseIf comLog(zInt).ToUpper.Contains("UNIT " & nWU.ID) AndAlso comLog(zInt).Contains("%") AndAlso Not comLog(zInt).ToUpper.Contains("LOAD") Then
                                                For xIP As Int32 = comLog(zInt).IndexOf("%") To 1 Step -1
                                                    If comLog(zInt).Substring(xIP, 1) = " " Or comLog(zInt).Substring(xIP, 1) = "(" Then
                                                        If nWU.Percentage = comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim Then
                                                            'Don't clear frames, continue parsing unit from xIP
                                                            'WriteDebug("Unit has been restarted from the same checkpoint, continue parsing from " & zInt)
                                                            iSkip = yInt
                                                            GoTo NextLine
                                                        ElseIf CInt(nWU.Percentage) > CInt(comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim) Then
                                                            'Clear frames before new percentage 
                                                            'WriteDebug("Unit has been restarted from " & comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim & ", clearing redundant frame info and continuing to parse unit from " & xInt)
                                                            nWU.ClearFrames(CInt(comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim))
                                                            'set iSkip to yInt and continue parsing
                                                            iSkip = yInt
                                                            GoTo NextLine
                                                        End If
                                                    End If
                                                Next
                                            End If
                                            '/zInt looking for frame start
                                        Next
                                    End If
                                    If yInt = xInt + 50 Then
                                        'WriteDebug("Finding upload or dump event is taking a long time!")
                                    ElseIf yInt = comLog.Count - 1 Then
                                        'WriteDebug("Can't find upload or dump event for this work unit!")
                                    End If
                                    '/yInt looking for upload or dump event 
                                Next
CreateSnippet2:
                                If iEnd = -1 Then iEnd = xInt + 25
                                Dim sbCS As New StringBuilder
                                For yInt As Int32 = iStart To iEnd
                                    'Add 'smart' filtering to for displaying log snippets
                                    sbCS.AppendLine(comLog(yInt))
                                Next
                                nWU.CoreSnippet = sbCS.ToString
                                'WriteDebug("Cores snippet assigned, storing work unit")
                                'sqData.SaveWorkUnit(ClientName, nWU)
                                lStart.lWU.Add(nWU)
                                iStored += 1
                                If lStart.ShowUI Then
                                    Bussy.SetMessage("Parsing logs for " & lStart.ClientName & Environment.NewLine & "Found " & iIndex & " work unit indexes" & Environment.NewLine & "- " & iStored & " finalized work units" & Environment.NewLine & "- " & iActive & " active work units")
                                End If
                                GoTo NextWU
                            ElseIf (comLog(xInt).ToUpper.Contains("FAHCORE, RUNNING UNIT " & nWU.ID) AndAlso comLog(xInt).ToUpper.Contains("RETURNED")) Or (comLog(xInt).ToUpper.Contains("FAHCORE RUNNING UNIT " & nWU.ID) AndAlso comLog(xInt).ToUpper.Contains("RETURNED")) Then
                                'Unit completion - corestatus - submitted - snippet
                                nWU.CoreStatus = comLog(xInt).Substring(comLog(xInt).ToUpper.IndexOf("RETURNED:") + 10)
                                nWU.dtCompleted = dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(xInt).Substring(0, 8)))
                                'WriteDebug("FahCore returned value: " & nWU.CoreStatus)
                                'Skipping CoreOutdated message.
                                If nWU.CoreStatus.Contains("110") Then
                                    'WriteDebug("Skipping core outdated message seems to work..")
                                    GoTo NextLine
                                ElseIf Not nWU.CoreStatus.Contains("FINISHED_UNIT") Then
                                    'WriteDebug("Work unit seems to have failed!")
                                End If
                                If comLog(xInt).Substring(comLog(xInt).ToUpper.IndexOf("RETURNED:") + 10).Contains("110") Then
                                    'Check if core is downloaded, what happens when the core can't be downloaded, does the client dump the unit and continue with a new one?
                                    GoTo NextLine  'seems to work if the result is either a 'failing' or 'dumping' message in the end
                                Else 'If Not comLog(xInt).Substring(comLog(xInt).IndexOf("returned:") + 10).Contains("100") Then
                                    'Check for snippet / restart 
                                    'WriteDebug("Searching for log snippet start")
                                    Dim iStart As Int32 = -1
                                    'iStart
                                    For zInt As Int32 = xInt To xInt - 50 Step -1
                                        If zInt = 0 Then
                                            'WriteDebug("Dump exited without start index")
                                            iStart = 0
                                            Exit For
                                        End If
                                        If (comLog(zInt).ToUpper.Contains("UNIT") AndAlso (Not comLog(zInt).IndexOf(nWU.ID, comLog(zInt).ToUpper.IndexOf("UNIT")) = -1) AndAlso comLog(zInt).Contains("%")) Then
                                            'WriteDebug("Dump exited due to last frame found")
                                            iStart = zInt
                                            Exit For
                                        ElseIf comLog(zInt).ToUpper.Contains("UNIT") AndAlso (Not comLog(zInt).IndexOf(nWU.ID, comLog(zInt).ToUpper.IndexOf("UNIT")) = -1) AndAlso comLog(zInt).ToUpper.Contains("ENTERING") Then
                                            'WriteDebug("Dump exited due to unit entering simulation")
                                            iStart = zInt
                                            Exit For
                                        ElseIf comLog(zInt).ToUpper.Contains("STARTING UNIT") AndAlso comLog(zInt).Contains(nWU.ID) Then
                                            'WriteDebug("Dump exited due to unit being started")
                                            iStart = zInt
                                            Exit For
                                        End If
                                    Next
                                    If iStart = -1 Then
                                        If xInt < 25 Then
                                            iStart = xInt - 25
                                            'WriteDebug("Setting istart to xInt - 25")
                                        Else
                                            iStart = 0
                                            'WriteDebug("Setting iStart to 0")
                                        End If
                                    End If
                                    'iEnd 
                                    Dim iEnd As Int32 = -1
                                    Dim iAddDays2 As Int32 = iAddDays
                                    For yInt As Int32 = xInt To comLog.Count - 1
                                        Try
                                            If CInt(comLog(yInt - 1).Replace(ChrW(34), "").Substring(0, 2)) > CInt(comLog(yInt).Replace(ChrW(34), "").Substring(0, 2)) Then
                                                iAddDays2 += 1
                                                'WriteDebug("Added a day to iAddDays2, current value:" & iAddDays2 & " - current date:" & dtStart.Date.AddDays(iAddDays2).Add(TimeSpan.Parse(comLog(yInt).Substring(0, 8))))
                                            End If
                                        Catch ex As Exception

                                        End Try
                                        '(Not comLog(zInt).IndexOf(nWU.ID, comLog(zInt).ToUpper.IndexOf("UNIT")) = -1)
                                        If comLog(yInt).ToUpper.Contains("UNIT") AndAlso (Not comLog(yInt).IndexOf(nWU.ID, comLog(yInt).ToUpper.IndexOf("UNIT")) = -1) AndAlso comLog(yInt).ToUpper.Contains("UPLOADING") Then
                                            Try
                                                nWU.dtStartUpload = dtStart.Date.AddDays(iAddDays2).Add(TimeSpan.Parse(comLog(yInt).Substring(0, 8)))
                                                nWU.UploadSize = comLog(yInt).Substring(comLog(yInt).ToUpper.IndexOf("UPLOADING ") + Len("UPLOADING "))
                                                If nWU.UploadSize.IndexOf(" ") > 0 Then
                                                    nWU.UploadSize = nWU.UploadSize.Substring(0, nWU.UploadSize.IndexOf(" "))
                                                End If
                                                If comLog(yInt).IndexOf(" to ") > 0 Then
                                                    nWU.CS = comLog(yInt).Substring(comLog(yInt).IndexOf(" to ") + 4)
                                                End If
                                                'WriteDebug("Detected upload, upload size:" & nWU.UploadSize & " CS:" & nWU.CS)
                                            Catch ex As Exception
                                                WriteLog("Detected upload for " & nWU.PRCG & "-" & nWU.unit, eSeverity.Debug)
                                                WriteLog("-line: " & comLog(yInt), eSeverity.Debug)
                                                WriteError(ex.Message, Err)
                                            End Try
                                        ElseIf comLog(yInt).ToUpper.Contains("UNIT " & nWU.ID) AndAlso comLog(yInt).ToUpper.Contains("UPLOAD COMPLETE") Then
                                            nWU.dtSubmitted = dtStart.Date.AddDays(iAddDays2).Add(TimeSpan.Parse(comLog(yInt).Substring(0, 8)))
                                            WriteLog("Detected succesfull submission at " & nWU.dtSubmitted.ToString, eSeverity.Debug)
                                            For zInt As Int32 = yInt To comLog.Count - 1
                                                'WriteDebug("Looking for server responce")
                                                If comLog(zInt).ToUpper.Contains("SERVER RESPONDED") Then
                                                    nWU.ServerResponce = comLog(zInt).Substring(comLog(zInt).ToUpper.IndexOf("SERVER RESPONDED") + Len("Server responded "))
                                                    'WriteDebug("Response found:" & nWU.ServerResponce & ", exiting for-next")
                                                    Exit For
                                                ElseIf comLog(zInt).ToUpper.Contains("FINAL CREDIT ESTIMATE") Then
                                                    nWU.Credit = CInt(comLog(yInt).Trim(Chr(10)).Substring(32).ToUpper.Replace("POINTS", "").Trim).ToString
                                                    'WriteDebug("Server reported credit estimate: " & nWU.Credit)
                                                ElseIf zInt > yInt + 50 Then
                                                    WriteLog("Server response is taking a long time :(", eSeverity.Debug)
                                                ElseIf zInt = comLog.Count - 1 Then
                                                    'WriteDebug("PERFORMANCE: Couldn't determin server response!")
                                                End If
                                                '/zInt for serverResponse
                                            Next
                                        ElseIf comLog(yInt).ToUpper.Contains("FINAL CREDIT ESTIMATE") Then
                                            nWU.Credit = CInt(comLog(yInt).Trim(Chr(10)).Substring(32).ToUpper.Replace("POINTS", "").Trim).ToString
                                            'WriteDebug("Server reported credit estimate: " & nWU.Credit)
                                        ElseIf comLog(yInt).ToUpper.Contains("CLEANING UP UNIT") AndAlso (Not comLog(yInt).IndexOf(nWU.ID, comLog(yInt).ToUpper.IndexOf("UNIT")) = -1) Then
                                            'This should not happen before any upload, server responce and credit estimate has been found
                                            iEnd = yInt
                                            'WriteDebug("Cleaning up detected, accrediting wu, setting iEnd and exiting for-next")
                                            nWU = AccreditWorkunit(nWU)
                                            GoTo CreateSnippet
                                        ElseIf comLog(yInt).ToUpper.Contains("STARTING UNIT") AndAlso (Not comLog(yInt).IndexOf(nWU.ID, comLog(yInt).ToUpper.IndexOf("UNIT")) = -1) Then
                                            'WriteDebug("Unit seems to be restarted")
                                            nWU.bHasRestarted = True
                                            If nWU.Frames.Count >= 1 Then
                                                nWU.restartInfo.AddRestart(nWU.CoreStatus, nWU.Frames(nWU.Frames.Count - 1))
                                            Else
                                                'Check!
                                                nWU.restartInfo.AddRestart(nWU.CoreStatus, New clsWU.clsFrame("06:29:02:Unit 18:Completed INVALID out of INVALID steps  (0%)", nWU.dtDownloaded))
                                            End If
                                            'Check to clear frames  ---  Check below condition!
                                            '09:30:35:WARNING: Unit 02: 's slot ID 3 no longer exists and there are no other matching slots, dumping
                                            '09:30:35:Sending unit results: id:02 state:SEND error:DUMPED project:5738 run:0 clone:518 gen:912 core:0x11 unit:0x013c4f964ecb6b1a039002060000166a
                                            '09:30:35:WARNING: Work server too old for dump report
                                            '09:30:35:Cleaning up Unit 02
                                            For zInt As Int32 = yInt To comLog.Count - 1
                                                If comLog(zInt).ToUpper.Contains("WARNING: UNIT") AndAlso (Not comLog(zInt).IndexOf(nWU.ID, comLog(zInt).ToUpper.IndexOf("UNIT")) = -1) AndAlso comLog(zInt).ToUpper.Contains("DUMPING") Then
                                                    'WriteDebug("Work unit is not restarted but dumped, check for upload/server response/credit and save work unit")
                                                    nWU.CoreStatus = "dumped"
                                                    nWU.dtCompleted = dtStart.Date.AddDays(iAddDays2).Add(TimeSpan.Parse(comLog(zInt).Substring(0, 8)))
                                                    'Upload/clean loop
                                                    Dim iAddDays3 As Int32 = iAddDays2
                                                    For kInt As Int32 = zInt To comLog.Count - 1
                                                        Try
                                                            If CInt(comLog(kInt - 1).Replace(ChrW(34), "").Substring(0, 2)) > CInt(comLog(kInt).Replace(ChrW(34), "").Substring(0, 2)) Then
                                                                iAddDays3 += 1
                                                                'WriteDebug("Added a day to iAddDays3, current value:" & iAddDays2 & " - current date:" & dtStart.Date.AddDays(iAddDays3).Add(TimeSpan.Parse(comLog(kInt).Substring(0, 8))))
                                                            End If
                                                        Catch ex As Exception

                                                        End Try
                                                        If comLog(kInt).ToUpper.Contains("UNIT " & nWU.ID & ": UPLOADING ") Then
                                                            Try
                                                                nWU.dtStartUpload = dtStart.Date.AddDays(iAddDays3).Add(TimeSpan.Parse(comLog(kInt).Substring(0, 8)))
                                                                nWU.UploadSize = comLog(kInt).Substring(comLog(kInt).IndexOf("Unit " & nWU.ID & ": Uploading ") + Len("Unit " & nWU.ID & ": Uploading "))
                                                                If nWU.UploadSize.IndexOf(" ") > 0 Then
                                                                    nWU.UploadSize = nWU.UploadSize.Substring(0, nWU.UploadSize.IndexOf(" "))
                                                                End If
                                                                If comLog(kInt).IndexOf(" to ") > 0 Then
                                                                    nWU.CS = comLog(kInt).Substring(comLog(kInt).IndexOf(" to ") + 4)
                                                                End If
                                                                'WriteDebug("Detected upload, upload size:" & nWU.UploadSize & " CS:" & nWU.CS)
                                                            Catch ex As Exception
                                                                'WriteDebug("Error trying to set the upload event of " & nWU.PRCG & "-" & nWU.unit)
                                                                WriteError(ex.Message, Err)
                                                            End Try
                                                        ElseIf comLog(kInt).ToUpper.Contains("UNIT " & nWU.ID & ": UPLOAD COMPLETE") Then
                                                            nWU.dtSubmitted = dtStart.Date.AddDays(iAddDays3).Add(TimeSpan.Parse(comLog(kInt).Substring(0, 8)))
                                                            'WriteDebug("Detected succesfull submission at " & nWU.dtSubmitted.ToString)
                                                            For pInt As Int32 = kInt To comLog.Count - 1
                                                                WriteLog("Looking for server responce", eSeverity.Debug)
                                                                If comLog(pInt).ToUpper.Contains("SERVER RESPONDED ") Then
                                                                    nWU.ServerResponce = comLog(pInt).Substring(comLog(pInt).IndexOf("Server responded ") + Len("Server responded "))
                                                                    'WriteDebug("Response found:" & nWU.ServerResponce & ", exiting for-next")
                                                                    Exit For
                                                                ElseIf pInt > yInt + 50 Then
                                                                    'WriteDebug("PERFORMANCE: Logparser performance suffering, not able to find server responce!")
                                                                ElseIf pInt = comLog.Count - 1 Then
                                                                    'WriteDebug("PERFORMANCE: Couldn't determin server response!")
                                                                End If
                                                                '/pInt for serverResponse
                                                            Next
                                                        ElseIf comLog(kInt).ToUpper.Contains("FINAL CREDIT ESTIMATE") Then
                                                            Try
                                                                nWU.Credit = CInt(comLog(kInt).Trim(Chr(10)).Substring(32).Replace(" points", "")).ToString
                                                            Catch ex As Exception
                                                                WriteError(ex.Message, Err)
                                                            Finally
                                                                'WriteDebug("Server reported credit estimate: " & nWU.Credit)
                                                            End Try
                                                        ElseIf comLog(kInt).ToUpper.Contains("CLEANING UP UNIT " & nWU.ID) Then
                                                            'Finalize wu
                                                            iEnd = kInt
                                                            'WriteDebug("Cleaning up detected, accrediting wu, setting iEnd and exiting for-next")
                                                            nWU = AccreditWorkunit(nWU)
                                                            GoTo CreateSnippet
                                                        End If
                                                        '/Upload/response/credit
                                                        Application.DoEvents()
                                                    Next
                                                ElseIf comLog(zInt).ToUpper.Contains("UNIT " & nWU.ID & ":PROJECT: ") Then
                                                    If Not comLog(zInt).ToUpper.Contains(nWU.Project & " (RUN " & nWU.Run & ", CLONE " & nWU.Clone & ", GEN " & nWU.Gen & ")") Then
                                                        WriteLog("WARNING: Unit " & nWU.unit & " parsing loop hit a snare!", eSeverity.Important)
                                                    End If
                                                ElseIf comLog(zInt).ToUpper.Contains("UNIT " & nWU.ID) AndAlso comLog(zInt).Contains("%") Then
                                                    For xIP As Int32 = comLog(zInt).IndexOf("%") To 1 Step -1
                                                        If comLog(zInt).Substring(xIP, 1) = " " Or comLog(zInt).Substring(xIP, 1) = "(" Then
                                                            Try
                                                                If nWU.Percentage = "" Then
                                                                    'Commented out iSkip, pointer is sometimes wrong!
                                                                    'WriteDebug("No frames to clear, continue from " & zInt.ToString)
                                                                    'iSkip = zInt
                                                                    GoTo NextLine
                                                                ElseIf nWU.Percentage = comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim Then
                                                                    'Don't clear frames, continue parsing unit from xIP
                                                                    'WriteDebug("Unit has been restarted from the same checkpoint, continue parsing from " & zInt)
                                                                    'iSkip = yInt
                                                                    GoTo NextLine
                                                                ElseIf CInt(nWU.Percentage) > CInt(comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim) Then
                                                                    'Clear frames before new percentage 
                                                                    'WriteDebug("Unit has been restarted from " & comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim & ", clearing redundant frame info and continuing to parse unit from " & zInt)
                                                                    nWU.ClearFrames(CInt(comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim))
                                                                    'nWU.AddFrame(comLog(zInt), dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(zInt).Substring(0, 8))))
                                                                    'set iSkip to yInt and continue parsing
                                                                    'iSkip = yInt
                                                                    GoTo NextLine
                                                                End If
                                                            Catch ex As Exception
                                                                WriteError(ex.Message, Err)
                                                            End Try
                                                        End If
                                                    Next
                                                ElseIf comLog(zInt).ToUpper.Contains("FAHCORE, RUNNING UNIT " & nWU.ID & ", RETURNED:") Or comLog(xInt).Contains("FAHCORE RUNNING UNIT " & nWU.ID & " RETURNED:") Then
                                                    WriteLog("CoreStatus detected, revert to zInt -1 and reparse!", eSeverity.Debug)
                                                    iSkip = zInt - 1
                                                    GoTo NextLine
                                                End If
                                                '/zInt looking for frame start
                                            Next
                                        End If
                                        If yInt = xInt + 50 Then
                                            WriteLog("Finding upload or dump event is taking a long time!", eSeverity.Debug)
                                        ElseIf yInt = comLog.Count - 1 Then
                                            WriteLog("Can't find upload or dump event for this work unit!", eSeverity.Debug)
                                        End If
                                        '/yInt looking for upload or dump event 
                                    Next
CreateSnippet:
                                    If iEnd = -1 Then iEnd = xInt + 25
                                    Dim sbCS As New StringBuilder
                                    For yInt As Int32 = iStart To iEnd
                                        'Add 'smart' filtering to for displaying log snippets
                                        sbCS.AppendLine(comLog(yInt))
                                    Next
                                    nWU.CoreSnippet = sbCS.ToString
                                    'WriteDebug("Cores snippet assigned, storing work unit")
                                    'sqData.SaveWorkUnit(ClientName, nWU)
                                    lStart.lWU.Add(nWU)
                                    iStored += 1
                                    If lStart.ShowUI Then
                                        Bussy.SetMessage("Parsing logs for " & lStart.ClientName & Environment.NewLine & "Found " & iIndex & " work unit indexes" & Environment.NewLine & "- " & iStored & " finalized work units" & Environment.NewLine & "- " & iActive & " active work units")
                                    End If
                                    GoTo NextWU
                                End If
                                '/
                            End If
                            '/xInt - line index for comlog parsing
NextLine:
                            'Application.DoEvents()
                            Try
                                If xInt = comLog.Count - 1 Then
                                    'Store not finalized work units in db with line index!
                                    iActive += 1
                                    lStart.lActiveWU.Add(nWU)
                                    Bussy.SetMessage("Parsing logs for " & lStart.ClientName & Environment.NewLine & "Found " & iIndex & " work unit indexes" & Environment.NewLine & "- " & iStored & " finalized work units" & Environment.NewLine & "- " & iActive & " active work units")
                                    Exit Do
                                End If

                                If iSkip = -1 Then
                                    xInt += 1
                                Else
                                    xInt = iSkip
                                    iSkip = -1
                                End If
                            Catch ex As Exception
                                'WriteDebug("Exception in unit parsing loop")
                                WriteError(ex.Message, Err)
                            End Try
                            '/xInt increment
                        Loop
NextWU:
                        '/nWU
                    Next
NextSection:
                Next

                With startLog
                    sqdata.SaveWorkUnit(.lWU, True)
                    For Each DictionaryEntry In .dClientInfo
                        If Not sqdata.HasClientInfo(startLog.ClientName, DictionaryEntry.Key) Then sqdata.SaveFAHClientInfo(startLog.ClientName, DictionaryEntry.Key, DictionaryEntry.Value.Info)
                    Next
                    Dim lAccounts As New List(Of String)
                    For Each DictionaryEntry In .dClientConfig
                        If Not lAccounts.Contains(DictionaryEntry.Value.User & "#" & DictionaryEntry.Value.Team) Then
                            lAccounts.Add(DictionaryEntry.Value.User & "#" & DictionaryEntry.Value.Team)
                        End If
                        For Each xUser As clsClientConfig.clsConfiguration.clsExtraUser In DictionaryEntry.Value.Configuration.ExtraUsers
                            If Not lAccounts.Contains(xUser.user & "#" & xUser.team) Then
                                lAccounts.Add(DictionaryEntry.Value.User & "#" & DictionaryEntry.Value.Team)
                            End If
                        Next
                        sqdata.SaveFAHClientConfig(startLog.ClientName, DictionaryEntry.Value.Configuration.ConfigurationDT, DictionaryEntry.Value.Configuration)
                    Next
                    For Each lFile As clsLogFile In .lLogFiles
                        If lFile.AllDone Then
                            sqdata.SetLogStored(startLog.ClientName, lFile.fileName, lFile.Log, CInt(lFile.LineCount))
                        End If
                    Next
                    For Each sLine As String In lAccounts
                        Dim user As String = sLine.Substring(0, sLine.IndexOf("#"))
                        Dim team As String = sLine.Substring(sLine.IndexOf("#") + 1)
                        EOC.AddAccount(user, team, , True)
                    Next
                    logParser.Client(lStart.ClientName).ClientConfig = .ClientConfig
                    logParser.Client(lStart.ClientName).ClientInfo = .ClientInfo
                    logParser.Client(lStart.ClientName).ActiveWU.Clear()
                    logParser.Client(lStart.ClientName).ActiveWU.AddRange(lStart.lActiveWU)
                    .clear()
                End With
            Catch ex As Exception
                WriteError(ex.Message, Err)
            End Try
        Catch ex As Exception
            WriteError(ex.Message, Err)
        Finally
            GC.Collect()
            If startLog.asThread Then Threading.Thread.CurrentThread.Abort()
        End Try
    End Sub
End Class
